/* ********************************************************************
 **********************************************************************
 * HTML Virtual Keyboard Interface Script - v1.49
 *   Copyright (c) 2011 - GreyWyvern
 *
 *  - Licenced for free distribution under the BSDL
 *          http://www.opensource.org/licenses/bsd-license.php
 *
 * Add a script-driven keyboard interface to text fields, password
 * fields and textareas.
 *
 * See http://www.greywyvern.com/code/javascript/keyboard for examples
 * and usage instructions.
 *
 * Version 1.49 - November 8, 2011
 *   - Don't display language drop-down if only one keyboard available
 *
 *   See full changelog at:
 *     http://www.greywyvern.com/code/javascript/keyboard.changelog.txt
 *
 * Keyboard Credits
 *   - Yiddish (Yidish Lebt) keyboard layout by Simche Taub (jidysz.net)
 *   - Urdu Phonetic keyboard layout by Khalid Malik
 *   - Yiddish keyboard layout by Helmut Wollmersdorfer
 *   - Khmer keyboard layout by Sovann Heng (km-kh.com)
 *   - Dari keyboard layout by Saif Fazel
 *   - Kurdish keyboard layout by Ara Qadir
 *   - Assamese keyboard layout by Kanchan Gogoi
 *   - Bulgarian BDS keyboard layout by Milen Georgiev
 *   - Basic Japanese Hiragana/Katakana keyboard layout by Damjan
 *   - Ukrainian keyboard layout by Dmitry Nikitin
 *   - Macedonian keyboard layout by Damjan Dimitrioski
 *   - Pashto keyboard layout by Ahmad Wali Achakzai (qamosona.com)
 *   - Armenian Eastern and Western keyboard layouts by Hayastan Project (www.hayastan.co.uk)
 *   - Pinyin keyboard layout from a collaboration with Lou Winklemann
 *   - Kazakh keyboard layout by Alex Madyankin
 *   - Danish keyboard layout by Verner Kjærsgaard
 *   - Slovak keyboard layout by Daniel Lara (www.learningslovak.com)
 *   - Belarusian and Serbian Cyrillic keyboard layouts by Evgeniy Titov
 *   - Bulgarian Phonetic keyboard layout by Samuil Gospodinov
 *   - Swedish keyboard layout by Håkan Sandberg
 *   - Romanian keyboard layout by Aurel
 *   - Farsi (Persian) keyboard layout by Kaveh Bakhtiyari (www.bakhtiyari.com)
 *   - Burmese keyboard layout by Cetanapa
 *   - Bosnian/Croatian/Serbian Latin/Slovenian keyboard layout by Miran Zeljko
 *   - Hungarian keyboard layout by Antal Sall 'Hiromacu'
 *   - Arabic keyboard layout by Srinivas Reddy
 *   - Italian and Spanish (Spain) keyboard layouts by dictionarist.com
 *   - Lithuanian and Russian keyboard layouts by Ramunas
 *   - German keyboard layout by QuHno
 *   - French keyboard layout by Hidden Evil
 *   - Polish Programmers layout by moose
 *   - Turkish keyboard layouts by offcu
 *   - Dutch and US Int'l keyboard layouts by jerone
 *
 */
var VKI_attach, VKI_close;
(function() {
    var self = this;

    this.VKI_version = "1.49";
    this.VKI_showVersion = false;
    this.VKI_target = false;
    this.VKI_shift = this.VKI_shiftlock = false;
    this.VKI_altgr = this.VKI_altgrlock = false;
    this.VKI_dead = false;
    this.VKI_deadBox = false; // Show the dead keys checkbox
    this.VKI_deadkeysOn = false;  // Turn dead keys on by default
    this.VKI_numberPad = true;  // Allow user to open and close the number pad
    this.VKI_numberPadOn = false;  // Show number pad by default
    this.VKI_kts = this.VKI_kt = "US International";  // Default keyboard layout
    this.VKI_langAdapt = true;  // Use lang attribute of input to select keyboard
    this.VKI_size = 3;  // Default keyboard size (1-5)
    this.VKI_sizeAdj = true;  // Allow user to adjust keyboard size
    this.VKI_clearPasswords = false;  // Clear password fields on focus
    this.VKI_imageURI = "images/keyboard.png";  // If empty string, use imageless mode
    this.VKI_clickless = 0;  // 0 = disabled, > 0 = delay in ms
    this.VKI_activeTab = 0;  // Tab moves to next: 1 = element, 2 = keyboard enabled element
    this.VKI_enterSubmit = true;  // Submit forms when Enter is pressed
    this.VKI_keyCenter = 3;

    this.VKI_isIE = /*@cc_on!@*/false;
    this.VKI_isIE6 = /*@if(@_jscript_version == 5.6)!@end@*/false;
    this.VKI_isIElt8 = /*@if(@_jscript_version < 5.8)!@end@*/false;
    this.VKI_isWebKit = RegExp("KHTML").test(navigator.userAgent);
    this.VKI_isOpera = RegExp("Opera").test(navigator.userAgent);
    this.VKI_isMoz = (!this.VKI_isWebKit && navigator.product == "Gecko");

    /* ***** i18n text strings ************************************* */
    this.VKI_i18n = {
        '00': "Display Number Pad",
        '01': "Display virtual keyboard interface",
        '02': "Select keyboard layout",
        '03': "Dead keys",
        '04': "On",
        '05': "Off",
        '06': "Close the keyboard",
        '07': "Clear",
        '08': "Clear this input",
        '09': "Version",
        '10': "Decrease keyboard size",
        '11': "Increase keyboard size"
    };


    /* ***** Create keyboards ************************************** */
    this.VKI_layout = {};

    // - Lay out each keyboard in rows of sub-arrays.  Each sub-array
    //   represents one key.
    //
    // - Each sub-array consists of four slots described as follows:
    //     example: ["a", "A", "\u00e1", "\u00c1"]
    //
    //          a) Normal character
    //          A) Character + Shift/Caps
    //     \u00e1) Character + Alt/AltGr/AltLk
    //     \u00c1) Character + Shift/Caps + Alt/AltGr/AltLk
    //
    //   You may include sub-arrays which are fewer than four slots.
    //   In these cases, the missing slots will be blanked when the
    //   corresponding modifier key (Shift or AltGr) is pressed.
    //
    // - If the second slot of a sub-array matches one of the following
    //   strings:
    //     "Tab", "Caps", "Shift", "Enter", "Bksp",
    //     "Alt" OR "AltGr", "AltLk"
    //   then the function of the key will be the following,
    //   respectively:
    //     - Insert a tab
    //     - Toggle Caps Lock (technically a Shift Lock)
    //     - Next entered character will be the shifted character
    //     - Insert a newline (textarea), or close the keyboard
    //     - Delete the previous character
    //     - Next entered character will be the alternate character
    //     - Toggle Alt/AltGr Lock
    //
    //   The first slot of this sub-array will be the text to display
    //   on the corresponding key.  This allows for easy localisation
    //   of key names.
    //
    // - Layout dead keys (diacritic + letter) should be added as
    //   property/value pairs of objects with hash keys equal to the
    //   diacritic.  See the "this.VKI_deadkey" object below the layout
    //   definitions.  In each property/value pair, the value is what
    //   the diacritic would change the property name to.
    //
    // - Note that any characters beyond the normal ASCII set should be
    //   entered in escaped Unicode format.  (eg \u00a3 = Pound symbol)
    //   You can find Unicode values for characters here:
    //     http://unicode.org/charts/
    //
    // - To remove a keyboard, just delete it, or comment it out of the
    //   source code. If you decide to remove the US International
    //   keyboard layout, make sure you change the default layout
    //   (this.VKI_kt) above so it references an existing layout.
    this.VKI_layout['US International'] = {
        'name': "US International", 'keys': [
            [["`", "~"], ["1", "!", "\u00a1", "\u00b9"], ["2", "@", "\u00b2"], ["3", "#", "\u00b3"], ["4", "$", "\u00a4", "\u00a3"], ["5", "%", "\u20ac"], ["6", "^", "\u00bc"], ["7", "&", "\u00bd"], ["8", "*", "\u00be"], ["9", "(", "\u2018"], ["0", ")", "\u2019"], ["-", "_", "\u00a5"], ["=", "+", "\u00d7", "\u00f7"], ["Bksp", "Bksp"]],
            [["Tab", "Tab"], ["q", "Q", "\u00e4", "\u00c4"], ["w", "W", "\u00e5", "\u00c5"], ["e", "E", "\u00e9", "\u00c9"], ["r", "R", "\u00ae"], ["t", "T", "\u00fe", "\u00de"], ["y", "Y", "\u00fc", "\u00dc"], ["u", "U", "\u00fa", "\u00da"], ["i", "I", "\u00ed", "\u00cd"], ["o", "O", "\u00f3", "\u00d3"], ["p", "P", "\u00f6", "\u00d6"], ["[", "{", "\u00ab"], ["]", "}", "\u00bb"], ["\\", "|", "\u00ac", "\u00a6"]],
            [["Caps", "Caps"], ["a", "A", "\u00e1", "\u00c1"], ["s", "S", "\u00df", "\u00a7"], ["d", "D", "\u00f0", "\u00d0"], ["f", "F"], ["g", "G"], ["h", "H"], ["j", "J"], ["k", "K"], ["l", "L", "\u00f8", "\u00d8"], [";", ":", "\u00b6", "\u00b0"], ["'", '"', "\u00b4", "\u00a8"], ["Enter", "Enter"]],
            [["Shift", "Shift"], ["z", "Z", "\u00e6", "\u00c6"], ["x", "X"], ["c", "C", "\u00a9", "\u00a2"], ["v", "V"], ["b", "B"], ["n", "N", "\u00f1", "\u00d1"], ["m", "M", "\u00b5"], [",", "<", "\u00e7", "\u00c7"], [".", ">"], ["/", "?", "\u00bf"], ["Shift", "Shift"]],
            [[" ", " ", " ", " "], ["Alt", "Alt"]]
        ], 'lang': ["en"] };


    /* ***** Define Dead Keys ************************************** */
    this.VKI_deadkey = {};

    // - Lay out each dead key set as an object of property/value
    //   pairs.  The rows below are wrapped so uppercase letters are
    //   below their lowercase equivalents.
    //
    // - The property name is the letter pressed after the diacritic.
    //   The property value is the letter this key-combo will generate.
    //
    // - Note that if you have created a new keyboard layout and want
    //   it included in the distributed script, PLEASE TELL ME if you
    //   have added additional dead keys to the ones below.

    this.VKI_deadkey['"'] = this.VKI_deadkey['\u00a8'] = this.VKI_deadkey['\u309B'] = { // Umlaut / Diaeresis / Greek Dialytika / Hiragana/Katakana Voiced Sound Mark
        'a': "\u00e4", 'e': "\u00eb", 'i': "\u00ef", 'o': "\u00f6", 'u': "\u00fc", 'y': "\u00ff", '\u03b9': "\u03ca", '\u03c5': "\u03cb", '\u016B': "\u01D6", '\u00FA': "\u01D8", '\u01D4': "\u01DA", '\u00F9': "\u01DC",
        'A': "\u00c4", 'E': "\u00cb", 'I': "\u00cf", 'O': "\u00d6", 'U': "\u00dc", 'Y': "\u0178", '\u0399': "\u03aa", '\u03a5': "\u03ab", '\u016A': "\u01D5", '\u00DA': "\u01D7", '\u01D3': "\u01D9", '\u00D9': "\u01DB",
        '\u304b': "\u304c", '\u304d': "\u304e", '\u304f': "\u3050", '\u3051': "\u3052", '\u3053': "\u3054", '\u305f': "\u3060", '\u3061': "\u3062", '\u3064': "\u3065", '\u3066': "\u3067", '\u3068': "\u3069",
        '\u3055': "\u3056", '\u3057': "\u3058", '\u3059': "\u305a", '\u305b': "\u305c", '\u305d': "\u305e", '\u306f': "\u3070", '\u3072': "\u3073", '\u3075': "\u3076", '\u3078': "\u3079", '\u307b': "\u307c",
        '\u30ab': "\u30ac", '\u30ad': "\u30ae", '\u30af': "\u30b0", '\u30b1': "\u30b2", '\u30b3': "\u30b4", '\u30bf': "\u30c0", '\u30c1': "\u30c2", '\u30c4': "\u30c5", '\u30c6': "\u30c7", '\u30c8': "\u30c9",
        '\u30b5': "\u30b6", '\u30b7': "\u30b8", '\u30b9': "\u30ba", '\u30bb': "\u30bc", '\u30bd': "\u30be", '\u30cf': "\u30d0", '\u30d2': "\u30d3", '\u30d5': "\u30d6", '\u30d8': "\u30d9", '\u30db': "\u30dc"
    };
    this.VKI_deadkey['~'] = { // Tilde / Stroke
        'a': "\u00e3", 'l': "\u0142", 'n': "\u00f1", 'o': "\u00f5",
        'A': "\u00c3", 'L': "\u0141", 'N': "\u00d1", 'O': "\u00d5"
    };
    this.VKI_deadkey['^'] = { // Circumflex
        'a': "\u00e2", 'e': "\u00ea", 'i': "\u00ee", 'o': "\u00f4", 'u': "\u00fb", 'w': "\u0175", 'y': "\u0177",
        'A': "\u00c2", 'E': "\u00ca", 'I': "\u00ce", 'O': "\u00d4", 'U': "\u00db", 'W': "\u0174", 'Y': "\u0176"
    };
    this.VKI_deadkey['\u02c7'] = { // Baltic caron
        'c': "\u010D", 'd': "\u010f", 'e': "\u011b", 's': "\u0161", 'l': "\u013e", 'n': "\u0148", 'r': "\u0159", 't': "\u0165", 'u': "\u01d4", 'z': "\u017E", '\u00fc': "\u01da",
        'C': "\u010C", 'D': "\u010e", 'E': "\u011a", 'S': "\u0160", 'L': "\u013d", 'N': "\u0147", 'R': "\u0158", 'T': "\u0164", 'U': "\u01d3", 'Z': "\u017D", '\u00dc': "\u01d9"
    };
    this.VKI_deadkey['\u02d8'] = { // Romanian and Turkish breve
        'a': "\u0103", 'g': "\u011f",
        'A': "\u0102", 'G': "\u011e"
    };
    this.VKI_deadkey['-'] = this.VKI_deadkey['\u00af'] = { // Macron
        'a': "\u0101", 'e': "\u0113", 'i': "\u012b", 'o': "\u014d", 'u': "\u016B", 'y': "\u0233", '\u00fc': "\u01d6",
        'A': "\u0100", 'E': "\u0112", 'I': "\u012a", 'O': "\u014c", 'U': "\u016A", 'Y': "\u0232", '\u00dc': "\u01d5"
    };
    this.VKI_deadkey['`'] = { // Grave
        'a': "\u00e0", 'e': "\u00e8", 'i': "\u00ec", 'o': "\u00f2", 'u': "\u00f9", '\u00fc': "\u01dc",
        'A': "\u00c0", 'E': "\u00c8", 'I': "\u00cc", 'O': "\u00d2", 'U': "\u00d9", '\u00dc': "\u01db"
    };
    this.VKI_deadkey["'"] = this.VKI_deadkey['\u00b4'] = this.VKI_deadkey['\u0384'] = { // Acute / Greek Tonos
        'a': "\u00e1", 'e': "\u00e9", 'i': "\u00ed", 'o': "\u00f3", 'u': "\u00fa", 'y': "\u00fd", '\u03b1': "\u03ac", '\u03b5': "\u03ad", '\u03b7': "\u03ae", '\u03b9': "\u03af", '\u03bf': "\u03cc", '\u03c5': "\u03cd", '\u03c9': "\u03ce", '\u00fc': "\u01d8",
        'A': "\u00c1", 'E': "\u00c9", 'I': "\u00cd", 'O': "\u00d3", 'U': "\u00da", 'Y': "\u00dd", '\u0391': "\u0386", '\u0395': "\u0388", '\u0397': "\u0389", '\u0399': "\u038a", '\u039f': "\u038c", '\u03a5': "\u038e", '\u03a9': "\u038f", '\u00dc': "\u01d7"
    };
    this.VKI_deadkey['\u02dd'] = { // Hungarian Double Acute Accent
        'o': "\u0151", 'u': "\u0171",
        'O': "\u0150", 'U': "\u0170"
    };
    this.VKI_deadkey['\u0385'] = { // Greek Dialytika + Tonos
        '\u03b9': "\u0390", '\u03c5': "\u03b0"
    };
    this.VKI_deadkey['\u00b0'] = this.VKI_deadkey['\u00ba'] = { // Ring
        'a': "\u00e5", 'u': "\u016f",
        'A': "\u00c5", 'U': "\u016e"
    };
    this.VKI_deadkey['\u02DB'] = { // Ogonek
        'a': "\u0106", 'e': "\u0119", 'i': "\u012f", 'o': "\u01eb", 'u': "\u0173", 'y': "\u0177",
        'A': "\u0105", 'E': "\u0118", 'I': "\u012e", 'O': "\u01ea", 'U': "\u0172", 'Y': "\u0176"
    };
    this.VKI_deadkey['\u02D9'] = { // Dot-above
        'c': "\u010B", 'e': "\u0117", 'g': "\u0121", 'z': "\u017C",
        'C': "\u010A", 'E': "\u0116", 'G': "\u0120", 'Z': "\u017B"
    };
    this.VKI_deadkey['\u00B8'] = this.VKI_deadkey['\u201a'] = { // Cedilla
        'c': "\u00e7", 's': "\u015F",
        'C': "\u00c7", 'S': "\u015E"
    };
    this.VKI_deadkey[','] = { // Comma
        's': (this.VKI_isIElt8) ? "\u015F" : "\u0219", 't': (this.VKI_isIElt8) ? "\u0163" : "\u021B",
        'S': (this.VKI_isIElt8) ? "\u015E" : "\u0218", 'T': (this.VKI_isIElt8) ? "\u0162" : "\u021A"
    };
    this.VKI_deadkey['\u3002'] = { // Hiragana/Katakana Point
        '\u306f': "\u3071", '\u3072': "\u3074", '\u3075': "\u3077", '\u3078': "\u307a", '\u307b': "\u307d",
        '\u30cf': "\u30d1", '\u30d2': "\u30d4", '\u30d5': "\u30d7", '\u30d8': "\u30da", '\u30db': "\u30dd"
    };


    /* ***** Define Symbols **************************************** */
    this.VKI_symbol = {
        '\u00a0': "NB\nSP", '\u200b': "ZW\nSP", '\u200c': "ZW\nNJ", '\u200d': "ZW\nJ"
    };


    /* ***** Layout Number Pad ************************************* */
    this.VKI_numpad = [
        [["$"], ["\u00a3"], ["\u20ac"], ["\u00a5"]],
        [["7"], ["8"], ["9"], ["/"]],
        [["4"], ["5"], ["6"], ["*"]],
        [["1"], ["2"], ["3"], ["-"]],
        [["0"], ["."], ["="], ["+"]]
    ];


    /* ****************************************************************
     * Attach the keyboard to an element
     *
     */
    VKI_attach = function(elem) {
        if (elem.getAttribute("VKI_attached")) return false;
        if (self.VKI_imageURI) {
            var keybut = document.createElement('img');
            keybut.src = self.VKI_imageURI;
            keybut.alt = self.VKI_i18n['01'];
            keybut.className = "keyboardInputInitiator";
            keybut.title = self.VKI_i18n['01'];
            keybut.elem = elem;
            keybut.onclick = function(e) {
                e = e || event;
                if (e.stopPropagation) { e.stopPropagation(); } else e.cancelBubble = true;
                self.VKI_show(this.elem);
            };
            elem.parentNode.insertBefore(keybut, (elem.dir == "rtl") ? elem : elem.nextSibling);
        } else {
            elem.onfocus = function() {
                if (self.VKI_target != this) {
                    if (self.VKI_target) self.VKI_close();
                    self.VKI_show(this);
                }
            };
            elem.onclick = function() {
                if (!self.VKI_target) self.VKI_show(this);
            }
        }
        elem.setAttribute("VKI_attached", 'true');
        if (self.VKI_isIE) {
            elem.onclick = elem.onselect = elem.onkeyup = function(e) {
                if ((e || event).type != "keyup" || !this.readOnly)
                    this.range = document.selection.createRange();
            };
        }
        VKI_addListener(elem, 'click', function(e) {
            if (self.VKI_target == this) {
                e = e || event;
                if (e.stopPropagation) { e.stopPropagation(); } else e.cancelBubble = true;
            } return false;
        }, false);
        if (self.VKI_isMoz)
            elem.addEventListener('blur', function() { this.setAttribute('_scrollTop', this.scrollTop); }, false);
    };


    /* ***** Find tagged input & textarea elements ***************** */
    function VKI_buildKeyboardInputs() {
        var inputElems = [
            document.getElementsByTagName('input'),
            document.getElementsByTagName('textarea')
        ];
        for (var x = 0, elem; elem = inputElems[x++];)
            for (var y = 0, ex; ex = elem[y++];)
                if (ex.nodeName == "TEXTAREA" || ex.type == "text" || ex.type == "password")
                    if (ex.className.indexOf("keyboardInput") > -1) VKI_attach(ex);

        VKI_addListener(document.documentElement, 'click', function(e) { self.VKI_close(); }, false);
    }


    /* ****************************************************************
     * Common mouse event actions
     *
     */
    function VKI_mouseEvents(elem) {
        if (elem.nodeName == "TD") {
            if (!elem.click) elem.click = function() {
                var evt = this.ownerDocument.createEvent('MouseEvents');
                evt.initMouseEvent('click', true, true, this.ownerDocument.defaultView, 1, 0, 0, 0, 0, false, false, false, false, 0, null);
                this.dispatchEvent(evt);
            };
            elem.VKI_clickless = 0;
            VKI_addListener(elem, 'dblclick', function() { return false; }, false);
        }
        VKI_addListener(elem, 'mouseover', function() {
            if (this.nodeName == "TD" && self.VKI_clickless) {
                var _self = this;
                clearTimeout(this.VKI_clickless);
                this.VKI_clickless = setTimeout(function() { _self.click(); }, self.VKI_clickless);
            }
            if (self.VKI_isIE) this.className += " hover";
        }, false);
        VKI_addListener(elem, 'mouseout', function() {
            if (this.nodeName == "TD") clearTimeout(this.VKI_clickless);
            if (self.VKI_isIE) this.className = this.className.replace(/ ?(hover|pressed) ?/g, "");
        }, false);
        VKI_addListener(elem, 'mousedown', function() {
            if (this.nodeName == "TD") clearTimeout(this.VKI_clickless);
            if (self.VKI_isIE) this.className += " pressed";
        }, false);
        VKI_addListener(elem, 'mouseup', function() {
            if (this.nodeName == "TD") clearTimeout(this.VKI_clickless);
            if (self.VKI_isIE) this.className = this.className.replace(/ ?pressed ?/g, "");
        }, false);
    }


    /* ***** Build the keyboard interface ************************** */
    this.VKI_keyboard = document.createElement('table');
    this.VKI_keyboard.id = "keyboardInputMaster";
    this.VKI_keyboard.dir = "ltr";
    this.VKI_keyboard.cellSpacing = "0";
    this.VKI_keyboard.reflow = function() {
        this.style.width = "50px";
        var foo = this.offsetWidth;
        this.style.width = "";
    };
    VKI_addListener(this.VKI_keyboard, 'click', function(e) {
        e = e || event;
        if (e.stopPropagation) { e.stopPropagation(); } else e.cancelBubble = true;
        return false;
    }, false);

    if (!this.VKI_layout[this.VKI_kt])
        return alert('No keyboard named "' + this.VKI_kt + '"');

    this.VKI_langCode = {};
    var thead = document.createElement('thead');
    var tr = document.createElement('tr');
    var th = document.createElement('th');
    th.colSpan = "2";

    var kbSelect = document.createElement('div');
    kbSelect.title = this.VKI_i18n['02'];
    VKI_addListener(kbSelect, 'click', function() {
        var ol = this.getElementsByTagName('ol')[0];
        if (!ol.style.display) {
            ol.style.display = "block";
            var li = ol.getElementsByTagName('li');
            for (var x = 0, scr = 0; x < li.length; x++) {
                if (VKI_kt == li[x].firstChild.nodeValue) {
                    li[x].className = "selected";
                    scr = li[x].offsetTop - li[x].offsetHeight * 2;
                } else li[x].className = "";
            } setTimeout(function() { ol.scrollTop = scr; }, 0);
        } else ol.style.display = "";
    }, false);
    kbSelect.appendChild(document.createTextNode(this.VKI_kt));
    kbSelect.appendChild(document.createTextNode(this.VKI_isIElt8 ? " \u2193" : " \u25be"));
    kbSelect.langCount = 0;
    var ol = document.createElement('ol');
    for (ktype in this.VKI_layout) {
        if (typeof this.VKI_layout[ktype] == "object") {
            if (!this.VKI_layout[ktype].lang) this.VKI_layout[ktype].lang = [];
            for (var x = 0; x < this.VKI_layout[ktype].lang.length; x++)
                this.VKI_langCode[this.VKI_layout[ktype].lang[x].toLowerCase().replace(/-/g, "_")] = ktype;
            var li = document.createElement('li');
            li.title = this.VKI_layout[ktype].name;
            VKI_addListener(li, 'click', function(e) {
                e = e || event;
                if (e.stopPropagation) { e.stopPropagation(); } else e.cancelBubble = true;
                this.parentNode.style.display = "";
                self.VKI_kts = self.VKI_kt = kbSelect.firstChild.nodeValue = this.firstChild.nodeValue;
                self.VKI_buildKeys();
                self.VKI_position(true);
            }, false);
            VKI_mouseEvents(li);
            li.appendChild(document.createTextNode(ktype));
            ol.appendChild(li);
            kbSelect.langCount++;
        }
    } kbSelect.appendChild(ol);
    if (kbSelect.langCount > 1) th.appendChild(kbSelect);
    this.VKI_langCode.index = [];
    for (prop in this.VKI_langCode)
        if (prop != "index" && typeof this.VKI_langCode[prop] == "string")
            this.VKI_langCode.index.push(prop);
    this.VKI_langCode.index.sort();
    this.VKI_langCode.index.reverse();

    if (this.VKI_numberPad) {
        var span = document.createElement('span');
        span.appendChild(document.createTextNode("#"));
        span.title = this.VKI_i18n['00'];
        VKI_addListener(span, 'click', function() {
            kbNumpad.style.display = (!kbNumpad.style.display) ? "none" : "";
            self.VKI_position(true);
        }, false);
        VKI_mouseEvents(span);
        th.appendChild(span);
    }

    this.VKI_kbsize = function(e) {
        self.VKI_size = Math.min(5, Math.max(1, self.VKI_size));
        self.VKI_keyboard.className = self.VKI_keyboard.className.replace(/ ?keyboardInputSize\d ?/, "");
        if (self.VKI_size != 2) self.VKI_keyboard.className += " keyboardInputSize" + self.VKI_size;
        self.VKI_position(true);
        if (self.VKI_isOpera) self.VKI_keyboard.reflow();
    };
    if (this.VKI_sizeAdj) {
        var small = document.createElement('small');
        small.title = this.VKI_i18n['10'];
        VKI_addListener(small, 'click', function() {
            --self.VKI_size;
            self.VKI_kbsize();
        }, false);
        VKI_mouseEvents(small);
        small.appendChild(document.createTextNode(this.VKI_isIElt8 ? "\u2193" : "\u21d3"));
        th.appendChild(small);
        var big = document.createElement('big');
        big.title = this.VKI_i18n['11'];
        VKI_addListener(big, 'click', function() {
            ++self.VKI_size;
            self.VKI_kbsize();
        }, false);
        VKI_mouseEvents(big);
        big.appendChild(document.createTextNode(this.VKI_isIElt8 ? "\u2191" : "\u21d1"));
        th.appendChild(big);
    }

    var span = document.createElement('span');
    span.appendChild(document.createTextNode(this.VKI_i18n['07']));
    span.title = this.VKI_i18n['08'];
    VKI_addListener(span, 'click', function() {
        self.VKI_target.value = "";
        self.VKI_target.focus();
        return false;
    }, false);
    VKI_mouseEvents(span);
    th.appendChild(span);

    var strong = document.createElement('strong');
    strong.appendChild(document.createTextNode('X'));
    strong.title = this.VKI_i18n['06'];
    VKI_addListener(strong, 'click', function() { self.VKI_close(); }, false);
    VKI_mouseEvents(strong);
    th.appendChild(strong);

    tr.appendChild(th);
    thead.appendChild(tr);
    this.VKI_keyboard.appendChild(thead);

    var tbody = document.createElement('tbody');
    var tr = document.createElement('tr');
    var td = document.createElement('td');
    var div = document.createElement('div');

    if (this.VKI_deadBox) {
        var label = document.createElement('label');
        var checkbox = document.createElement('input');
        checkbox.type = "checkbox";
        checkbox.title = this.VKI_i18n['03'] + ": " + ((this.VKI_deadkeysOn) ? this.VKI_i18n['04'] : this.VKI_i18n['05']);
        checkbox.defaultChecked = this.VKI_deadkeysOn;
        VKI_addListener(checkbox, 'click', function() {
            this.title = self.VKI_i18n['03'] + ": " + ((this.checked) ? self.VKI_i18n['04'] : self.VKI_i18n['05']);
            self.VKI_modify("");
            return true;
        }, false);
        label.appendChild(checkbox);
        checkbox.checked = this.VKI_deadkeysOn;
        div.appendChild(label);
        this.VKI_deadkeysOn = checkbox;
    } else this.VKI_deadkeysOn.checked = this.VKI_deadkeysOn;

    if (this.VKI_showVersion) {
        var vr = document.createElement('var');
        vr.title = this.VKI_i18n['09'] + " " + this.VKI_version;
        vr.appendChild(document.createTextNode("v" + this.VKI_version));
        div.appendChild(vr);
    } td.appendChild(div);
    tr.appendChild(td);

    var kbNumpad = document.createElement('td');
    kbNumpad.id = "keyboardInputNumpad";
    if (!this.VKI_numberPadOn) kbNumpad.style.display = "none";
    var ntable = document.createElement('table');
    ntable.cellSpacing = "0";
    var ntbody = document.createElement('tbody');
    for (var x = 0; x < this.VKI_numpad.length; x++) {
        var ntr = document.createElement('tr');
        for (var y = 0; y < this.VKI_numpad[x].length; y++) {
            var ntd = document.createElement('td');
            VKI_addListener(ntd, 'click', VKI_keyClick, false);
            VKI_mouseEvents(ntd);
            ntd.appendChild(document.createTextNode(this.VKI_numpad[x][y]));
            ntr.appendChild(ntd);
        } ntbody.appendChild(ntr);
    } ntable.appendChild(ntbody);
    kbNumpad.appendChild(ntable);
    tr.appendChild(kbNumpad);
    tbody.appendChild(tr);
    this.VKI_keyboard.appendChild(tbody);

    if (this.VKI_isIE6) {
        this.VKI_iframe = document.createElement('iframe');
        this.VKI_iframe.style.position = "absolute";
        this.VKI_iframe.style.border = "0px none";
        this.VKI_iframe.style.filter = "mask()";
        this.VKI_iframe.style.zIndex = "999999";
        this.VKI_iframe.src = this.VKI_imageURI;
    }


    /* ****************************************************************
     * Private table cell attachment function for generic characters
     *
     */
    function VKI_keyClick() {
        var done = false, character = "\xa0";
        if (this.firstChild.nodeName.toLowerCase() != "small") {
            if ((character = this.firstChild.nodeValue) == "\xa0") return false;
        } else character = this.firstChild.getAttribute('char');
        if (self.VKI_deadkeysOn.checked && self.VKI_dead) {
            if (self.VKI_dead != character) {
                if (character != " ") {
                    if (self.VKI_deadkey[self.VKI_dead][character]) {
                        self.VKI_insert(self.VKI_deadkey[self.VKI_dead][character]);
                        done = true;
                    }
                } else {
                    self.VKI_insert(self.VKI_dead);
                    done = true;
                }
            } else done = true;
        } self.VKI_dead = false;

        if (!done) {
            if (self.VKI_deadkeysOn.checked && self.VKI_deadkey[character]) {
                self.VKI_dead = character;
                this.className += " dead";
                if (self.VKI_shift) self.VKI_modify("Shift");
                if (self.VKI_altgr) self.VKI_modify("AltGr");
            } else self.VKI_insert(character);
        } self.VKI_modify("");
        return false;
    }


    /* ****************************************************************
     * Build or rebuild the keyboard keys
     *
     */
    this.VKI_buildKeys = function() {
        this.VKI_shift = this.VKI_shiftlock = this.VKI_altgr = this.VKI_altgrlock = this.VKI_dead = false;
        var container = this.VKI_keyboard.tBodies[0].getElementsByTagName('div')[0];
        var tables = container.getElementsByTagName('table');
        for (var x = tables.length - 1; x >= 0; x--) container.removeChild(tables[x]);

        for (var x = 0, hasDeadKey = false, lyt; lyt = this.VKI_layout[this.VKI_kt].keys[x++];) {
            var table = document.createElement('table');
            table.cellSpacing = "0";
            if (lyt.length <= this.VKI_keyCenter) table.className = "keyboardInputCenter";
            var tbody = document.createElement('tbody');
            var tr = document.createElement('tr');
            for (var y = 0, lkey; lkey = lyt[y++];) {
                var td = document.createElement('td');
                if (this.VKI_symbol[lkey[0]]) {
                    var text = this.VKI_symbol[lkey[0]].split("\n");
                    var small = document.createElement('small');
                    small.setAttribute('char', lkey[0]);
                    for (var z = 0; z < text.length; z++) {
                        if (z) small.appendChild(document.createElement("br"));
                        small.appendChild(document.createTextNode(text[z]));
                    } td.appendChild(small);
                } else td.appendChild(document.createTextNode(lkey[0] || "\xa0"));

                var className = [];
                if (this.VKI_deadkeysOn.checked)
                    for (key in this.VKI_deadkey)
                        if (key === lkey[0]) { className.push("deadkey"); break; }
                if (lyt.length > this.VKI_keyCenter && y == lyt.length) className.push("last");
                if (lkey[0] == " " || lkey[1] == " ") className.push("space");
                td.className = className.join(" ");

                switch (lkey[1]) {
                    case "Caps": case "Shift":
                    case "Alt": case "AltGr": case "AltLk":
                    VKI_addListener(td, 'click', (function(type) { return function() { self.VKI_modify(type); return false; }})(lkey[1]), false);
                    break;
                    case "Tab":
                        VKI_addListener(td, 'click', function() {
                            if (self.VKI_activeTab) {
                                if (self.VKI_target.form) {
                                    var target = self.VKI_target, elems = target.form.elements;
                                    self.VKI_close();
                                    for (var z = 0, me = false, j = -1; z < elems.length; z++) {
                                        if (j == -1 && elems[z].getAttribute("VKI_attached")) j = z;
                                        if (me) {
                                            if (self.VKI_activeTab == 1 && elems[z]) break;
                                            if (elems[z].getAttribute("VKI_attached")) break;
                                        } else if (elems[z] == target) me = true;
                                    } if (z == elems.length) z = Math.max(j, 0);
                                    if (elems[z].getAttribute("VKI_attached")) {
                                        self.VKI_show(elems[z]);
                                    } else elems[z].focus();
                                } else self.VKI_target.focus();
                            } else self.VKI_insert("\t");
                            return false;
                        }, false);
                        break;
                    case "Bksp":
                        VKI_addListener(td, 'click', function() {
                            self.VKI_target.focus();
                            if (self.VKI_target.setSelectionRange && !self.VKI_target.readOnly) {
                                var rng = [self.VKI_target.selectionStart, self.VKI_target.selectionEnd];
                                if (rng[0] < rng[1]) rng[0]++;
                                self.VKI_target.value = self.VKI_target.value.substr(0, rng[0] - 1) + self.VKI_target.value.substr(rng[1]);
                                self.VKI_target.setSelectionRange(rng[0] - 1, rng[0] - 1);
                            } else if (self.VKI_target.createTextRange && !self.VKI_target.readOnly) {
                                try {
                                    self.VKI_target.range.select();
                                } catch(e) { self.VKI_target.range = document.selection.createRange(); }
                                if (!self.VKI_target.range.text.length) self.VKI_target.range.moveStart('character', -1);
                                self.VKI_target.range.text = "";
                            } else self.VKI_target.value = self.VKI_target.value.substr(0, self.VKI_target.value.length - 1);
                            if (self.VKI_shift) self.VKI_modify("Shift");
                            if (self.VKI_altgr) self.VKI_modify("AltGr");
                            self.VKI_target.focus();
                            return true;
                        }, false);
                        break;
                    case "Enter":
                        VKI_addListener(td, 'click', function() {
                            if (self.VKI_target.nodeName != "TEXTAREA") {
                                if (self.VKI_enterSubmit && self.VKI_target.form) {
                                    for (var z = 0, subm = false; z < self.VKI_target.form.elements.length; z++)
                                        if (self.VKI_target.form.elements[z].type == "submit") subm = true;
                                    if (!subm) self.VKI_target.form.submit();
                                }
                                self.VKI_close();
                            } else self.VKI_insert("\n");
                            return true;
                        }, false);
                        break;
                    default:
                        VKI_addListener(td, 'click', VKI_keyClick, false);

                } VKI_mouseEvents(td);
                tr.appendChild(td);
                for (var z = 0; z < 4; z++)
                    if (this.VKI_deadkey[lkey[z] = lkey[z] || ""]) hasDeadKey = true;
            } tbody.appendChild(tr);
            table.appendChild(tbody);
            container.appendChild(table);
        }
        if (this.VKI_deadBox)
            this.VKI_deadkeysOn.style.display = (hasDeadKey) ? "inline" : "none";
        if (this.VKI_isIE6) {
            this.VKI_iframe.style.width = this.VKI_keyboard.offsetWidth + "px";
            this.VKI_iframe.style.height = this.VKI_keyboard.offsetHeight + "px";
        }
    };

    this.VKI_buildKeys();
    VKI_addListener(this.VKI_keyboard, 'selectstart', function() { return false; }, false);
    this.VKI_keyboard.unselectable = "on";
    if (this.VKI_isOpera)
        VKI_addListener(this.VKI_keyboard, 'mousedown', function() { return false; }, false);


    /* ****************************************************************
     * Controls modifier keys
     *
     */
    this.VKI_modify = function(type) {
        switch (type) {
            case "Alt":
            case "AltGr": this.VKI_altgr = !this.VKI_altgr; break;
            case "AltLk": this.VKI_altgr = 0; this.VKI_altgrlock = !this.VKI_altgrlock; break;
            case "Caps": this.VKI_shift = 0; this.VKI_shiftlock = !this.VKI_shiftlock; break;
            case "Shift": this.VKI_shift = !this.VKI_shift; break;
        } var vchar = 0;
        if (!this.VKI_shift != !this.VKI_shiftlock) vchar += 1;
        if (!this.VKI_altgr != !this.VKI_altgrlock) vchar += 2;

        var tables = this.VKI_keyboard.tBodies[0].getElementsByTagName('div')[0].getElementsByTagName('table');
        for (var x = 0; x < tables.length; x++) {
            var tds = tables[x].getElementsByTagName('td');
            for (var y = 0; y < tds.length; y++) {
                var className = [], lkey = this.VKI_layout[this.VKI_kt].keys[x][y];

                switch (lkey[1]) {
                    case "Alt":
                    case "AltGr":
                        if (this.VKI_altgr) className.push("pressed");
                        break;
                    case "AltLk":
                        if (this.VKI_altgrlock) className.push("pressed");
                        break;
                    case "Shift":
                        if (this.VKI_shift) className.push("pressed");
                        break;
                    case "Caps":
                        if (this.VKI_shiftlock) className.push("pressed");
                        break;
                    case "Tab": case "Enter": case "Bksp": break;
                    default:
                        if (type) {
                            tds[y].removeChild(tds[y].firstChild);
                            if (this.VKI_symbol[lkey[vchar]]) {
                                var text = this.VKI_symbol[lkey[vchar]].split("\n");
                                var small = document.createElement('small');
                                small.setAttribute('char', lkey[vchar]);
                                for (var z = 0; z < text.length; z++) {
                                    if (z) small.appendChild(document.createElement("br"));
                                    small.appendChild(document.createTextNode(text[z]));
                                } tds[y].appendChild(small);
                            } else tds[y].appendChild(document.createTextNode(lkey[vchar] || "\xa0"));
                        }
                        if (this.VKI_deadkeysOn.checked) {
                            var character = tds[y].firstChild.nodeValue || tds[y].firstChild.className;
                            if (this.VKI_dead) {
                                if (character == this.VKI_dead) className.push("pressed");
                                if (this.VKI_deadkey[this.VKI_dead][character]) className.push("target");
                            }
                            if (this.VKI_deadkey[character]) className.push("deadkey");
                        }
                }

                if (y == tds.length - 1 && tds.length > this.VKI_keyCenter) className.push("last");
                if (lkey[0] == " " || lkey[1] == " ") className.push("space");
                tds[y].className = className.join(" ");
            }
        }
    };


    /* ****************************************************************
     * Insert text at the cursor
     *
     */
    this.VKI_insert = function(text) {
        this.VKI_target.focus();
        if (this.VKI_target.maxLength) this.VKI_target.maxlength = this.VKI_target.maxLength;
        if (typeof this.VKI_target.maxlength == "undefined" ||
            this.VKI_target.maxlength < 0 ||
            this.VKI_target.value.length < this.VKI_target.maxlength) {
            if (this.VKI_target.setSelectionRange && !this.VKI_target.readOnly && !this.VKI_isIE) {
                var rng = [this.VKI_target.selectionStart, this.VKI_target.selectionEnd];
                this.VKI_target.value = this.VKI_target.value.substr(0, rng[0]) + text + this.VKI_target.value.substr(rng[1]);
                if (text == "\n" && this.VKI_isOpera) rng[0]++;
                this.VKI_target.setSelectionRange(rng[0] + text.length, rng[0] + text.length);
            } else if (this.VKI_target.createTextRange && !this.VKI_target.readOnly) {
                try {
                    this.VKI_target.range.select();
                } catch(e) { this.VKI_target.range = document.selection.createRange(); }
                this.VKI_target.range.text = text;
                this.VKI_target.range.collapse(true);
                this.VKI_target.range.select();
            } else this.VKI_target.value += text;
            if (this.VKI_shift) this.VKI_modify("Shift");
            if (this.VKI_altgr) this.VKI_modify("AltGr");
            this.VKI_target.focus();
        } else if (this.VKI_target.createTextRange && this.VKI_target.range)
            this.VKI_target.range.select();
    };


    /* ****************************************************************
     * Show the keyboard interface
     *
     */
    this.VKI_show = function(elem) {
        if (!this.VKI_target) {
            this.VKI_target = elem;
            if (this.VKI_langAdapt && this.VKI_target.lang) {
                var chg = false, sub = [], lang = this.VKI_target.lang.toLowerCase().replace(/-/g, "_");
                for (var x = 0, chg = false; !chg && x < this.VKI_langCode.index.length; x++)
                    if (lang.indexOf(this.VKI_langCode.index[x]) == 0)
                        chg = kbSelect.firstChild.nodeValue = this.VKI_kt = this.VKI_langCode[this.VKI_langCode.index[x]];
                if (chg) this.VKI_buildKeys();
            }
            if (this.VKI_isIE) {
                if (!this.VKI_target.range) {
                    this.VKI_target.range = this.VKI_target.createTextRange();
                    this.VKI_target.range.moveStart('character', this.VKI_target.value.length);
                } this.VKI_target.range.select();
            }
            try { this.VKI_keyboard.parentNode.removeChild(this.VKI_keyboard); } catch (e) {}
            if (this.VKI_clearPasswords && this.VKI_target.type == "password") this.VKI_target.value = "";

            var elem = this.VKI_target;
            this.VKI_target.keyboardPosition = "absolute";
            do {
                if (VKI_getStyle(elem, "position") == "fixed") {
                    this.VKI_target.keyboardPosition = "fixed";
                    break;
                }
            } while (elem = elem.offsetParent);

            if (this.VKI_isIE6) document.body.appendChild(this.VKI_iframe);
            document.body.appendChild(this.VKI_keyboard);
            this.VKI_keyboard.style.position = this.VKI_target.keyboardPosition;
            if (this.VKI_isOpera) this.VKI_keyboard.reflow();

            this.VKI_position(true);
            if (self.VKI_isMoz || self.VKI_isWebKit) this.VKI_position(true);
            this.VKI_target.blur();
            this.VKI_target.focus();
        } else this.VKI_close();
    };


    /* ****************************************************************
     * Position the keyboard
     *
     */
    this.VKI_position = function(force) {
        if (self.VKI_target) {
            var kPos = VKI_findPos(self.VKI_keyboard), wDim = VKI_innerDimensions(), sDis = VKI_scrollDist();
            var place = false, fudge = self.VKI_target.offsetHeight + 3;
            if (force !== true) {
                if (kPos[1] + self.VKI_keyboard.offsetHeight - sDis[1] - wDim[1] > 0) {
                    place = true;
                    fudge = -self.VKI_keyboard.offsetHeight - 3;
                } else if (kPos[1] - sDis[1] < 0) place = true;
            }
            if (place || force === true) {
                var iPos = VKI_findPos(self.VKI_target), scr = self.VKI_target;
                while (scr = scr.parentNode) {
                    if (scr == document.body) break;
                    if (scr.scrollHeight > scr.offsetHeight || scr.scrollWidth > scr.offsetWidth) {
                        if (!scr.getAttribute("VKI_scrollListener")) {
                            scr.setAttribute("VKI_scrollListener", true);
                            VKI_addListener(scr, 'scroll', function() { self.VKI_position(true); }, false);
                        } // Check if the input is in view
                        var pPos = VKI_findPos(scr), oTop = iPos[1] - pPos[1], oLeft = iPos[0] - pPos[0];
                        var top = oTop + self.VKI_target.offsetHeight;
                        var left = oLeft + self.VKI_target.offsetWidth;
                        var bottom = scr.offsetHeight - oTop - self.VKI_target.offsetHeight;
                        var right = scr.offsetWidth - oLeft - self.VKI_target.offsetWidth;
                        self.VKI_keyboard.style.display = (top < 0 || left < 0 || bottom < 0 || right < 0) ? "none" : "";
                        if (self.VKI_isIE6) self.VKI_iframe.style.display = (top < 0 || left < 0 || bottom < 0 || right < 0) ? "none" : "";
                    }
                }
                self.VKI_keyboard.style.top = iPos[1] - ((self.VKI_target.keyboardPosition == "fixed" && !self.VKI_isIE && !self.VKI_isMoz) ? sDis[1] : 0) + fudge + "px";
                self.VKI_keyboard.style.left = Math.max(10, Math.min(wDim[0] - self.VKI_keyboard.offsetWidth - 25, iPos[0])) + "px";
                if (self.VKI_isIE6) {
                    self.VKI_iframe.style.width = self.VKI_keyboard.offsetWidth + "px";
                    self.VKI_iframe.style.height = self.VKI_keyboard.offsetHeight + "px";
                    self.VKI_iframe.style.top = self.VKI_keyboard.style.top;
                    self.VKI_iframe.style.left = self.VKI_keyboard.style.left;
                }
            }
            if (force === true) self.VKI_position();
        }
    };


    /* ****************************************************************
     * Close the keyboard interface
     *
     */
    this.VKI_close = VKI_close = function() {
        if (this.VKI_target) {
            try {
                this.VKI_keyboard.parentNode.removeChild(this.VKI_keyboard);
                if (this.VKI_isIE6) this.VKI_iframe.parentNode.removeChild(this.VKI_iframe);
            } catch (e) {}
            if (this.VKI_kt != this.VKI_kts) {
                kbSelect.firstChild.nodeValue = this.VKI_kt = this.VKI_kts;
                this.VKI_buildKeys();
            } kbSelect.getElementsByTagName('ol')[0].style.display = "";;
            this.VKI_target.focus();
            if (this.VKI_isIE) {
                setTimeout(function() { self.VKI_target = false; }, 0);
            } else this.VKI_target = false;
        }
    };


    /* ***** Private functions *************************************** */
    function VKI_addListener(elem, type, func, cap) {
        if (elem.addEventListener) {
            elem.addEventListener(type, function(e) { func.call(elem, e); }, cap);
        } else if (elem.attachEvent)
            elem.attachEvent('on' + type, function() { func.call(elem); });
    }

    function VKI_findPos(obj) {
        var curleft = curtop = 0, scr = obj;
        while ((scr = scr.parentNode) && scr != document.body) {
            curleft -= scr.scrollLeft || 0;
            curtop -= scr.scrollTop || 0;
        }
        do {
            curleft += obj.offsetLeft;
            curtop += obj.offsetTop;
        } while (obj = obj.offsetParent);
        return [curleft, curtop];
    }

    function VKI_innerDimensions() {
        if (self.innerHeight) {
            return [self.innerWidth, self.innerHeight];
        } else if (document.documentElement && document.documentElement.clientHeight) {
            return [document.documentElement.clientWidth, document.documentElement.clientHeight];
        } else if (document.body)
            return [document.body.clientWidth, document.body.clientHeight];
        return [0, 0];
    }

    function VKI_scrollDist() {
        var html = document.getElementsByTagName('html')[0];
        if (html.scrollTop && document.documentElement.scrollTop) {
            return [html.scrollLeft, html.scrollTop];
        } else if (html.scrollTop || document.documentElement.scrollTop) {
            return [html.scrollLeft + document.documentElement.scrollLeft, html.scrollTop + document.documentElement.scrollTop];
        } else if (document.body.scrollTop)
            return [document.body.scrollLeft, document.body.scrollTop];
        return [0, 0];
    }

    function VKI_getStyle(obj, styleProp) {
        if (obj.currentStyle) {
            var y = obj.currentStyle[styleProp];
        } else if (window.getComputedStyle)
            var y = window.getComputedStyle(obj, null)[styleProp];
        return y;
    }


    VKI_addListener(window, 'resize', this.VKI_position, false);
    VKI_addListener(window, 'scroll', this.VKI_position, false);
    this.VKI_kbsize();
    VKI_addListener(window, 'load', VKI_buildKeyboardInputs, false);
    // VKI_addListener(window, 'load', function() {
    //   setTimeout(VKI_buildKeyboardInputs, 5);
    // }, false);
})();